home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / macros / lamstex / inputs / dvipaste.tex < prev    next >
Text File  |  1991-09-06  |  14KB  |  332 lines

  1. % Copyright (C) The TeXplorators Corporation 1989
  2.  
  3. % This is DVIPASTE.TEX, to be used with DVIPASTE.EXE, which is
  4. % Copyright (C) The TeXplorators Corporation 1989.
  5.  
  6. % First we want to have a control sequence that stands for the current
  7. % category code of @, so that we can restore this category code at the end,
  8. % after temporarily making @ a letter (PLAIN makes @ category 12, but
  9. % AmS-TeX, for example, makes @ category 13). Using \csname CCC@\endcsname,
  10. % we can even let this control sequence be called \CCC@, before actually
  11. % making @ a letter, except that this won't work when @ has category 
  12. % code 13, so instead we have to use the \uccode and \uppercase trick.
  13.  
  14. {\uccode`\Z=`\@
  15.  \uppercase{\expandafter\xdef\csname CCCZ\endcsname{\the\catcode`\@}}
  16. }
  17.  
  18. % Now we make @ a letter.
  19.  
  20. \catcode`\@=11  
  21.  
  22.  
  23. % \eat@ gobbles a token; it is the same as in AmS-TeX.
  24.  
  25. \def\eat@#1{}
  26.  
  27.  
  28. % We need to know if a \sendout or \paste has already occurred.  The
  29. % following are made true once the respective condition has occurred.
  30.  
  31. \newif\ifsendout@  
  32. \newif\ifpaste@    
  33.  
  34.  
  35. % We need to allocate places for writing or reading the .dat file.
  36.  
  37. \newwrite\writedata@    
  38. \newread\readdata@      
  39.  
  40.  
  41. % The definition of \sendout has the following features (%1, %2, etc.
  42. % refer to lines so marked within the definition of \sendout):
  43.  
  44. %1  If \paste has occurred, we won't allow a \sendout to occur, because
  45. %   these shouldn't both occur in the same file; in fact, files having
  46. %   \sendout's will redefine the \output routine.
  47.  
  48. %   In the \errmessage, we can't say \string\sendout, because \sendout is
  49. %   outer.  So we use \expandafter\eat@\string\\ to get the \, and then
  50. %   spell out sendout.
  51.  
  52. %2  If a \paste hasn't occurred, we see if a previous \sendout has occurred,
  53. %   and if it hasn't, we do the following:
  54.     
  55. %3  Open the .dat file for writing.
  56.     
  57. %4  Declare \t@nrm to use for the name of the file and the page number
  58. %   in the footline (it is possible that no font with the necessary
  59. %   characters in it has been used in the file); the declaration is made 
  60. %   \global, just in case \sendout was used in a group, though it really 
  61. %   shouldn't be.
  62.     
  63. %5  Set \topskip to 0pt.
  64.  
  65. %6  Change the \output routine, to simply \shipout the current page,
  66. %   followed by a line 2pc below with the name of the file, and the
  67. %   page number.
  68.     
  69. %7  We also want to redefine \bye, to close out the .dat file.  We can't
  70. %   put \gdef\bye within the definition of \sendout, since \bye is outer,
  71. %   but we can say \expandafter\gdef\csname bye\endcsname !
  72.     
  73. %8  And we make \ifsendout@ true.
  74.     
  75. %9  In any case (i.e., whether or not a previous \sendout has occurred),
  76. %   we now put #1 in \box0, so that we can refer to its height, depth and
  77. %   width (usually #1 will be a \box, but we don't know which one).
  78.     
  79. %10 Then we write this data to the .dat file; each \space will expand to a
  80. %   space (PLAIN has \def\space{ }).
  81.     
  82. %11 We start the page with an invisible \hrule (so that the next \vskip
  83. %   won't disappear).
  84.     
  85. %12 We move down to the bottom of the page.
  86.  
  87. %13 We emit a special, which tells where the .dvi instructions for
  88. %   printing \box0 begin.
  89.     
  90. %14 We set the dimensions of \box0 to 0pt.
  91.     
  92. %15 We start an unindented paragraph with \box0.
  93.  
  94. %16 Then we emit another special, which tells where the .dvi instructions
  95. %   for printing \box0 end.
  96.     
  97. %17 Finally, we put in a smashed (and tiny) \vrule.  Since this \vrule
  98. %   has to occur exactly at the same position where the \noindent began,
  99. %   the .dvi instructions for printing \box0 will bring us right back to
  100. %   the position we started at.
  101.     
  102. %18 Then we \eject, so that the \output routine will simply print \box0 on 
  103. %   a separate page.
  104.  
  105. \outer\def\sendout#1{%          
  106.   \ifpaste@                                                                 %1
  107.     \errmessage{\expandafter\eat@\string\\sendout and 
  108.       \string\paste\space not allowed in same file 
  109.       (\string\paste\space has already appeared)}%
  110.   \else                                                                     %2
  111.     \ifsendout@                                                             
  112.     \else                                                                   
  113.       \immediate\openout\writedata@=\jobname.dat                            %3
  114.      \global\font\t@nrm=cmr10                                              %4
  115.       \global\topskip\z@                                                    %5
  116.       \global\output{\shipout\vbox{\vbox to\vsize{\unvbox255 }%             %6
  117.       \baselineskip2pc
  118.       \line{\hfil\t@nrm File [\jobname], \#\number\pageno\hfil}}%
  119.         \global\advance\pageno\@ne}%
  120.       \expandafter\gdef\csname bye\endcsname                                %7
  121.         {\immediate\closeout\writedata@\par\vfill\supereject\end}%
  122.       \global\sendout@true                                                  %8
  123.     \fi
  124.     \setbox\z@\hbox{#1}%                                                    %9
  125.     \immediate\write\writedata@
  126.       {\the\ht\z@\space\the\dp\z@\space\the\wd\z@}%                        %10
  127.     \hrule height\z@                                                       %11
  128.     \vskip\vsize                                                           %12
  129.     \special{beginpaste:}%                                                 %13
  130.     \ht\z@=\z@\dp\z@=\z@\wd\z@=\z@                                         %14
  131.     \noindent\box\z@                                                       %15
  132.     \special{endpaste:}%                                                   %16
  133.     \smash{\vrule height1sp width1sp depth\z@}%                            %17
  134.     \eject                                                                 %18
  135.   \fi}
  136.  
  137.  
  138. % The scratch tokens \toks@@ are already used in AmS-TeX.
  139.  
  140. \toksdef\toks@@=2
  141.  
  142.  
  143. % \rightappend@ is from The TeXbook, page 378.
  144.  
  145. \long\def\rightappend@#1\to#2{\toks@{\\{#1}}%
  146.   \toks@@=\expandafter{#2}\xdef#2{\the\toks@@\the\toks@}}
  147.  
  148.  
  149. % \ifreading@ will be true while still reading the data file; it is simply
  150. % the opposite of \ifeof, but we need an \if... with these reversed values,
  151. % to use within a \loop.
  152.  
  153. \newif\ifreading@  
  154.  
  155.  
  156. % The last line of the data file will produce a \par, so we need to have
  157. % something to test against \par.
  158.  
  159. \def\Par@{\par}    
  160.  
  161.  
  162. % The definition of \paste has the following features:
  163.  
  164. %1  If \sendout has occurred, we won't allow a \paste to occur.
  165.  
  166. %2  If a \paste hasn't occurred, we do the following:
  167.  
  168. %3  We make \ifpaste@ true.
  169.  
  170. %4  When we read in a data file `file'.dat, we will record all the data
  171. %   in a control sequence \`file'@dat. This will be a list macro, as in 
  172. %   The TeXbook, page 378.
  173.  
  174. %   To see whether we have read in the data file yet, we just see whether
  175. %   this control sequence, as specified by \csname, is \relax.
  176.  
  177. %5  If not, we haven't read the file yet, so we immediately open it for
  178. %   reading.
  179.  
  180. %6  We use \ifeof to test whether the file really exists.
  181.  
  182. %7  Assuming the file does exist, we do the following.
  183.  
  184. %8  We are going to temporarily store the data in the control sequence
  185. %   \next@, and at the end \let\`file'@dat=\next@.  We do this because it
  186. %   is rather awkward to continually refer to the control sequence
  187. %   \`file'@dat, which can only be named using \csname.  We begin by
  188. %   setting \next@ to be empty.
  189.  
  190. %9  We set \ifreading@ to be true (it will be false when we get to the
  191. %   end of the data file).
  192.  
  193. %10 We read using a \loop.
  194.  
  195. %11 The \loop needs a test that is true if we are going to keep reading,
  196. %   so we set \ifreading@ false when \ifeof gives true.
  197.  
  198. %12 If we are still reading the file, we read a line to \next@ii.  
  199.  
  200. %13 The file has a \par at the end, so \ifx\next@ii\Par@ is true when we
  201. %   are at the last line. 
  202.  
  203. %14 If that is not the case, then we want to add the data in \next@ii to
  204. %   \next@.  We need \expandafter\rightappend@; otherwise we would just
  205. %   get \next@ii in the token list, rather than the values it now has.
  206.  
  207. %15 And we just keep doing that until the file is all read.
  208.  
  209. %16 Then we close the file.
  210.  
  211. %17 And then we want to \global\let\`file'@dat=\next@.  We need to expand
  212. %   the \csname...\endcsname after a \global\let, which requires the
  213. %   triple \expandafter trick of The TeXbook, page 374.
  214.  
  215. %18 In any case (i.e., whether or not we first had to read in the data
  216. %   file), we now want to apply the \getdata@ construction, defined
  217. %   below, to \`file'@dat and the second argument #2 of \paste.  This
  218. %   also requires an \expandafter.
  219.  
  220. %19 \ifgetdata@ will be true if #2 is actually the number of a line in
  221. %   the data file.
  222.  
  223. %20 In this case, the three pieces of data will be stored in \data@ht,
  224. %   \data@dp, and \data@wd, and we will want to put in a box of that
  225. %   height, depth and width.  The easiest way is to lower a box of that
  226. %   height+depth by the depth, so we first set \dimen@ to that sum.
  227.  
  228. %21 We make an \hbox containing the special, and then the empty box with 
  229. %   the desired dimensions. NOTE: It is important to put the \special
  230. %   in the \hbox, in case this empty box turns out to be the first
  231. %   thing on the page.  For some reason, \tex\ doesn't position such
  232. %   an empty box at the right place, although it does position anything
  233. %   that will actually appear on the page in the right place; a box
  234. %   with a \special in it is NOT treated as an empty box in this process.
  235.  
  236. %22 If #2 is not the number of a line in the data file, we just give an
  237. %   error message ``No data for File [<data file>], #[<value of #2>]''
  238. %   In order to have # appear in the error message, rather than ##, we
  239. %   temporarily make # the \lccode of Z, put Z where we want the # to 
  240. %   appear, and then \lowercase the \errmessage.  However, we want to
  241. %   have uppercase N and F in this message, so we have to also set
  242. %   the \lccode of N to N, and of F to F.
  243.  
  244.  
  245. \def\paste#1#2{%
  246.   \ifsendout@                                                              %1
  247.     \errmessage{\string\paste\space and
  248.       \expandafter\eat@\string\\sendout not allowed in same file
  249.       (\expandafter\eat@\string\\sendout has already appeared)}%
  250.   \else                                                                    %2
  251.     \global\paste@true                                                     %3
  252.     \expandafter\ifx\csname #1@dat\endcsname\relax                         %4
  253.       \immediate\openin\readdata@=#1.dat                                   %5
  254.       \ifeof\readdata@\errmessage{No file #1.dat}%                         %6
  255.       \else                                                                %7
  256.         \def\next@{}%                                                      %8
  257.         \reading@true                                                      %9
  258.         \loop                                                              %10
  259.           \ifeof\readdata@\reading@false\fi                                %11
  260.           \ifreading@                                                      %12
  261.           \read\readdata@ to\next@ii  
  262.           \ifx\next@ii\Par@\else                                           %13
  263.             \expandafter\rightappend@\next@ii\to\next@\fi                  %14
  264.         \repeat                                                            %15
  265.         \immediate\closein\readdata@                                       %16
  266.         \expandafter\expandafter\expandafter\global\expandafter
  267.           \let\csname#1@dat\endcsname\next@                                %17
  268.       \fi
  269.     \fi
  270.     \expandafter\getdata@\csname#1@dat\endcsname{#2}%                      %18
  271.     \ifgetdata@                                                            %19
  272.       \dimen@=\data@ht\advance\dimen@\data@dp                              %20
  273.       \hbox{\special{dvipaste: #1 #2}%                                     %21
  274.       \lower\data@dp\vbox to\dimen@{\hbox to\data@wd{\hfil}\vfil}}%
  275.     \else                                                                  %22
  276.      {\lccode`\Z=`\#\lccode`\N=`\N\lccode`\F=`\F%
  277.      \lowercase{\errmessage{No data for File [#1], Z#2}}}%
  278.     \fi
  279.   \fi}
  280.  
  281.  
  282. % \data@ht, \data@dp, and \data@wd are registers in which \getdata@ will
  283. % store the data gotten.
  284.  
  285. \newdimen\data@ht
  286. \newdimen\data@dp
  287. \newdimen\data@wd
  288.  
  289.  
  290. % We also use a flag \ifgetdata@ to tell whether there was data on the line
  291. % requested.
  292.  
  293. \newif\ifgetdata@
  294.  
  295.  
  296. %  Argument #1 for \getdata@ is a list macro, and #2 a number.
  297.  
  298. %1 We start by setting the counter \count@ to 0, and \ifgetdata@ to
  299. %  false.
  300.  
  301. %2 We temporarily (i.e., within a group), define \\ to: (a) advance
  302. %  \count@ by 1 (so that \count@ is k when we are looking at the kth
  303. %  thing on the list); (b) if \count@=#2 (we are at the element of the
  304. %  lists specified by #2), set \ifgetdata@ true (so it is true only if
  305. %  there are at least #2 pieces of data); (c) and then use \getdata@@ to
  306. %  get the data out of this piece.  
  307.  
  308. %3 And then we apply this \\ to the list.
  309.  
  310.  
  311. \def\getdata@#1#2{\count@\z@\getdata@false                                 %1
  312.   {\def\\##1{\advance\count@\@ne\ifnum\count@=#2\relax\global\getdata@true
  313.      \getdata@@##1\getdata@@\fi                                            %2
  314.   }#1}}                                                                    %3
  315.  
  316.  
  317. % The elements of the list macro will be of the form
  318.  
  319. %   [...]pt [...]pt [...]pt
  320.  
  321. %  with a space after the first and second pt, so we just have \getdata@
  322. %  delimit its first two arguments with spaces.
  323.  
  324.  
  325. \def\getdata@@#1 #2 #3\getdata@@{%
  326.   \global\data@ht=#1\relax\global\data@dp=#2\relax\global\data@wd=#3\relax}
  327.  
  328.  
  329. % Finally, we return @ to its old \catcode.
  330.  
  331. \catcode`\@\CCC@
  332.